﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;

namespace ClipboardEx
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        protected static extern int SetClipboardViewer(int hWndNewViewer);

        [DllImport("user32.dll", CharSet=CharSet.Ansi)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

        [DllImport("user32.dll", CharSet = CharSet.Ansi)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint control, Keys vk);

        [DllImport("user32.dll")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        IntPtr mNextClipboardViewer;

        public static appconfig SConfig = new appconfig();

        ConfigFormcs mConfig;
        AboutBox1 mAbout;
        List<object> mObjs;
        bool mPass = false; // 忽略一次粘贴消息
        string mWinname = "超级剪贴板";
        bool mRealClose = false;

        const int HotKeyID = 0x88;
        const uint MOD_ALT = 0x0001;
        const uint MOD_CONTROL = 0x0002;
        const uint MOD_SHIFT = 0x0004;

        public Form1()
        {
            InitializeComponent();

            string exepath = Application.StartupPath;
            if (!SConfig.LoadConfig(exepath + "\\config.xml"))
            {
                SConfig.SetDefatult();
            }

            mObjs = new List<object>(100);

            mNextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);

            // 注册快捷键
            HotkeyRegister();

        }

        public void HotkeyRegister()
        {
            UnregisterHotKey(this.Handle, HotKeyID);

            Keys code;
            Keys mKey;
            Enum.TryParse(SConfig.GetConfig(appconfig.EConfigTxt.CONFIGSTR_K1), out code);
            Enum.TryParse(SConfig.GetConfig(appconfig.EConfigTxt.CONFIGSTR_K2), out mKey);

            uint key = 0;
            switch (code)
            {
                case Keys.Control:
                    key = MOD_CONTROL;
                    break;
                case Keys.Shift:
                    key = MOD_SHIFT;
                    break;
                default:
                    key = MOD_ALT;
                    break;
            }
            if (!RegisterHotKey(this.Handle, HotKeyID, key, mKey))
            {
                MessageBox.Show("注册热键失败!");
            }
        }

        public void ShowWindowFront()
        {
            // 窗口置顶显示
            if (!Visible)
            {
                Show();
            }
            SetForegroundWindow(this.Handle);
        }

        public void UpdateWindowTitle()
        {
            if (mObjs.Count == 0)
            {
                this.Text = mWinname;
            }
            else
            {
                this.Text = mWinname + " (" + mObjs.Count.ToString() + ")";
            }
        }

        protected override void WndProc(ref Message m)
        {
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;
            const int WM_HOTKEY = 0x0312;
            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    {
                        // 剪贴板内容发生改变
                        if (!mPass)
                        {
                            addNewData();
                        }

                        SendMessage(mNextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        mPass = false;
                    }
                    break;
                case WM_CHANGECBCHAIN:
                    {
                        if (m.WParam == mNextClipboardViewer)
                        {
                            mNextClipboardViewer = m.LParam;
                        }
                        else
                        {
                            SendMessage(mNextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        }
                    }
                    break;
                case WM_HOTKEY:
                    {
                        // 热键消息
                        if (m.WParam.ToInt32() == HotKeyID)
                        {
                            ShowWindowFront();
                        }
                    }
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        private void addNewData()
        {
            // 遍历数据类型
            IDataObject io = Clipboard.GetDataObject();
            string[] strs = io.GetFormats();

            if (strs.Length == 0)
            {
                // Do nothing
                return;
            }

            string formats = "";
            EItemType type = EItemType.EIT_UNKNOW;
            Dictionary<string, object> contents = new Dictionary<string, object>();
            bool getIt = false;
            foreach (string str in strs)
            {
                if (str == DataFormats.Text)
                {
                    type = EItemType.EIT_TEXT;
                    formats = (string)io.GetData(DataFormats.Text);
                    getIt = true;
                }
                else if (str == "FileNameW")
                {
                    object name = io.GetData("FileNameW");
                    string[] ss = (string[])name;
                    formats = ss[0];
                    FileInfo info = new FileInfo(formats);
                    if ((info.Attributes & FileAttributes.Directory) != 0)
                    {
                        type = EItemType.EIT_DIR;
                    }
                    else
                    {
                        type = EItemType.EIT_FILE;
                    }
                    getIt = true;
                }
                else
                {
                    if (!getIt)
                    {
                        formats += str;
                        formats += " ";
                    }
                }

                contents.Add(str, io.GetData(str));
            }

            // 移除重复的 fixed
            ListItemEx item = new ListItemEx(formats);
            item.EType = type;
            int index = listBox1.Items.IndexOf(item);

            delDataToObjs(index);

            // 是否有最大限制
            if (mObjs.Count >= SConfig.MaxRecord && 
                SConfig.MaxRecord != 0)
            {
                return;
            }
            else
            {
                listBox1.Items.Insert(0, item);
                mObjs.Insert(0, contents);
            }

            LightCopy(0);

            UpdateWindowTitle();

            if (SConfig.PopWhenClipChange)
            {
                ShowWindowFront();
            }
        }

        private void LightCopy(int index)
        {
            listBox1.SelectedIndex = index;
        }

        private void 设置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (mConfig == null)
            {
                mConfig = new ConfigFormcs();
            }

            if (!mConfig.Visible)
            {
                mConfig.ShowDialog(this);
            }
        }

        private void 打开ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Visible)
            {
                Hide();
            }
            else
            {
                Show();
            }
        }

        private void 设置ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            设置ToolStripMenuItem_Click(sender, e);
        }

        private void 帮助ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            帮助ToolStripMenuItem_Click(sender, e);
        }

        private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (mAbout == null)
            {
                mAbout = new AboutBox1();
            }

            if (!mAbout.Visible)
            {
                mAbout.ShowDialog(this);
            }
        }

        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mRealClose = true;
            UnregisterHotKey(this.Handle, HotKeyID);
            Close();
        }

        void setDataToClipboard(int index)
        {
            if (index >= mObjs.Count || index < 0)
            {
                return;
            }

            ListItemEx item = (ListItemEx)listBox1.Items[index];
            // 检查文件或目录是否存在
            if (item.Type == ListboxEx.TypeString[1])
            {
                FileInfo info = new FileInfo(item.Name);
                if (!info.Exists)
                {
                    delDataToObjs(index);
                    UpdateWindowTitle();
                    return;
                }
            }
            mPass = true;
            DataObject o = new DataObject();
            Dictionary<string, object> c = (Dictionary<string, object>)mObjs[index];
            foreach(string format in c.Keys)
            {
                o.SetData(format, c[format]);
            }
            LightCopy(index);
            Clipboard.SetDataObject(o);
        }

        void delDataToObjs(int index)
        {
            if (index >= mObjs.Count || index < 0)
            {
                return;
            }

            mObjs.RemoveAt(index);
            listBox1.Items.RemoveAt(index);
        }

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            if (!Visible)
            {
                Visible = true;
            }

            ShowWindowFront();
        }

        private void listBox1_MouseUp(object sender, MouseEventArgs e)
        {
            ListBox lb = (ListBox)sender;
            int index = lb.IndexFromPoint(e.X, e.Y);

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    setDataToClipboard(index);
                    break;

                case System.Windows.Forms.MouseButtons.Right:
                    delDataToObjs(index);
                    UpdateWindowTitle();
                    break;
            }
        }


        private void 全部清理ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            mObjs.Clear();

            UpdateWindowTitle();
        }

        private void 清理头10条ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count <= 10)
            {
                return;
            }

            int delPos = listBox1.Items.Count - 10;
            for (int i = 0; i < 10; ++i)
            {
                listBox1.Items.RemoveAt(delPos);
            }

            if (mObjs.Count <= 10)
            {
                return;
            }
            mObjs.RemoveRange(mObjs.Count - 10, 10);

            UpdateWindowTitle();
        }

        private void 清理头20条ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count <= 20)
            {
                return;
            }

            int delPos = listBox1.Items.Count - 20;
            for (int i = 0; i < 20; ++i)
            {
                listBox1.Items.RemoveAt(delPos);
            }

            if (mObjs.Count <= 20)
            {
                return;
            }
            mObjs.RemoveRange(mObjs.Count - 20, 20);

            UpdateWindowTitle();
        }

        private void 保留最后10条ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count <= 10)
            {
                return;
            }

            int count = listBox1.Items.Count - 10;
            for (int i = 0; i < count; ++i)
            {
                listBox1.Items.RemoveAt(10);
            }

            if (mObjs.Count <= 10)
            {
                return;
            }
            mObjs.RemoveRange(10, mObjs.Count - 10);

            UpdateWindowTitle();
        }

        private void 保留最后1条ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count <= 1)
            {
                return;
            }

            ListItemEx item = (ListItemEx)listBox1.Items[0];
            listBox1.Items.Clear();
            listBox1.Items.Add(item);

            if (mObjs.Count <= 1)
            {
                return;
            }
            mObjs.RemoveRange(1, mObjs.Count - 1);

            UpdateWindowTitle();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (SConfig.CloseForMin && !mRealClose)
            {
                Visible = false;
                e.Cancel = true;
            }
            else
            {
                e.Cancel = false;
            }
        }
    }
}
